package br.requisiteworks.modelo.dao.jpa;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import br.requisiteworks.modelo.Funcionario;
import br.requisiteworks.modelo.dao.ClienteDao;
import br.requisiteworks.modelo.dao.FuncionarioDao;
import br.requisiteworks.util.persistencia.ErroBancoDados;
import br.requisiteworks.util.persistencia.ResultadoVazio;

/**
 * Implementacao JPA do {@link ClienteDao}
 * 
 * @author Mikhail Domanoski
 * 
 * @version 2, 07/05/2010
 * 
 */
@Repository
public class JpaFuncionarioDao implements FuncionarioDao {

	@PersistenceContext
	private EntityManager em;

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void insert(Funcionario funcionario) throws ErroBancoDados {
		try {
			em.persist(funcionario);
			em.flush();
		} catch (PersistenceException e) {
			throw new ErroBancoDados(
					"Ocorreu um erro ao adicionar funcionario: " + funcionario,
					e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void update(Funcionario funcionario) throws ErroBancoDados {
		try {
			em.merge(funcionario);
			em.flush();
		} catch (PersistenceException e) {
			throw new ErroBancoDados(
					"Ocorreu um erro ao atualizar funcionario: " + funcionario,
					e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(Funcionario funcionario) throws ErroBancoDados {
		try {
			funcionario.setRegistroAtivo(false);
			this.update(funcionario);
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao deletar funcionario: "
					+ funcionario, e);
		}
	}

	@Override
	public Funcionario select(int numero) throws ResultadoVazio {
		Funcionario reference = em.find(Funcionario.class, numero);

		if (reference == null) {
			throw new ResultadoVazio(
					"Nao foi encontrado funcionario de numero = " + numero);
		}
		return reference;
	}

	@Override
	public List<Funcionario> select(String nome) throws ResultadoVazio {
		TypedQuery<Funcionario> query = em
				.createQuery(
						"SELECT DISTINCT OBJECT(f) FROM Funcionario f WHERE UPPER(f.nome) LIKE UPPER(:nome) and f.registroAtivo=true",
						Funcionario.class);
		query.setParameter("nome", "%" + nome + "%");
		List<Funcionario> resultado = query.getResultList();

		if (resultado == null || resultado.isEmpty()) {
			throw new ResultadoVazio(
					"Nao foi encontrado funcionario com nome = " + nome);
		}

		return resultado;
	}

	@Override
	public List<Funcionario> select() throws ResultadoVazio {
		TypedQuery<Funcionario> query = em
				.createQuery(
						"SELECT DISTINCT OBJECT(f) FROM Funcionario f WHERE f.registroAtivo=true",
						Funcionario.class);
		List<Funcionario> resultado = query.getResultList();

		if (resultado == null || resultado.isEmpty()) {
			throw new ResultadoVazio(
					"Nao foi encontrado nenhum registro de funcionario ativo");
		}

		return resultado;
	}
}
